#include "Flight.h"
#include "Bullet.h"
#include "Background.h"

#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>

#include <ctime>
#define enemyNum 10
void framebuffer_size_callback(GLFWwindow* window, int width, int height);

char processInput(GLFWwindow *window);


int main()
{
    HMODULE hModule = ::LoadLibrary(TEXT("bass.dll"));
    if (!hModule)
    {
        printf("加载bass.dll失败!\n");
        return -1;
    }
    BASS_Init(-1, 44100, 0, 0, NULL);


    srand(time(nullptr));
    Game game(600,900);
    GLFWwindow* window=game.createWindow();
    unsigned int VBO, VAO, EBO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);
    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *) 0);
    glEnableVertexAttribArray(0);
    // color attribute
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *) (3 * sizeof(float)));
    glEnableVertexAttribArray(1);
    // texture coord attribute
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *) (6 * sizeof(float)));
    glEnableVertexAttribArray(2);
    glBindVertexArray(VAO);

    Shader ourShader(FileSystem::getPath("res/4.1.texture.vs").c_str(),
                   FileSystem::getPath("res/4.1.texture.fs").c_str());
    //string sound=FileSystem::getPath("res/explosion1.wav");
    string expsound="res/explosion1.wav";
    HSTREAM shiftBullet=BASS_StreamCreateFile(FALSE, FileSystem::getPath("res/bulletshift.mp3").c_str(), 0, 0, 0);
    vector<Flight*>myFlight;
    vector<Bullet*>myBullet;
    vector<Flight*>enemyFlight;
    vector<Bullet*>enemyBullet;
    Flight* flight1=new Flight({"res/flight.png","res/explosion1-1.png","res/explosion1-2.png","res/explosion1-3.png"},expsound,{100,300},
            false,40,60,5,100);
    float randPos;
    for (int j = 0; j < enemyNum; ++j) {
        randPos=(rand()%Game::Width)*0.8;
        Flight* enemy=new Flight({"res/enemy1.png","res/explosion1-1.png","res/explosion1-2.png","res/explosion1-3.png"},expsound,{randPos,(float )game.Height},
                true,20,30,1,10);
        enemyFlight.push_back(enemy);
    }
    myFlight.push_back(flight1);

    // render loop
    // -----------
    GLfloat deltaTime = 0.0f;
    GLfloat lastTime = 0.0f;
    int count0=0,count1=0;
    char userInput;
    int backV=30;
    Background backGround0({"res/background.png"},{0,0},game.Width,game.Height,backV);
    Background background1({"res/background.png"},{0,(float)game.Height},game.Width,game.Height,backV);
    //窗口部分

    while (!glfwWindowShouldClose(window))
    {
        GLfloat currentTime=glfwGetTime();
        deltaTime=currentTime-lastTime;
        lastTime=currentTime;
        count0++;count1++;
        if(deltaTime>0.1) continue;
        glClearColor(0, 0, 0, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
        userInput=game.ProcessInput(window);

        backGround0.drawImage(ourShader);
        background1.drawImage(ourShader);

        backGround0.move(deltaTime);
        background1.move(deltaTime);
        backGround0.Init();
        background1.Init();

        myFlight[0]->move(userInput);
        myFlight[0]->drawImage(ourShader);
        if(myFlight[0]->HP<=0){
            if(myFlight[0]->explode(currentTime,ourShader)) {
                printf("Game over!\n");
                break;
            }
        }
        if(count0>15&&userInput==' '){
            count0=0;
            myBullet.push_back(myFlight[0]->shoot());

        }
        if(count1>50&&userInput=='F'){
            count1=0;
            myFlight[0]->changeBullet();
            BASS_ChannelPlay(shiftBullet, FALSE);
        }



        for (vector<Bullet*>::iterator it = myBullet.begin();it!=myBullet.end();) {
            if(myBullet.empty()){
                break;
            }
            (*it)->drawImage(ourShader);
            if((*it)->checkEdge()||(*it)->checkCollision(enemyFlight)||(*it)->have_been_exploded){
                if((*it)->explode(currentTime,ourShader)){
                    delete (*it);
                    myBullet.erase(it);
                    continue;
                }
            }
            if(!(*it)->have_been_exploded){
                (*it)->move('W',deltaTime);
            }
            it++;
        }//check Bullet;



        for(vector<Flight*>::iterator it=enemyFlight.begin();it!=enemyFlight.end();){
            if(enemyFlight.empty()) break;
            if((*it)->startTime>currentTime) {it++;continue;}
            (*it)->count++;
            if((*it)->count>100){
                (*it)->enemyDir=(*it)->randDir();
                enemyBullet.push_back((*it)->shoot());
                (*it)->count=0;
            }
            (*it)->move((*it)->enemyDir);
            (*it)->drawImage(ourShader);
            if((*it)->HP<=0){
                if((*it)->explode(currentTime,ourShader)){
                    delete (*it);
                    enemyFlight.erase(it);
                    continue;
                }
            }
            it++;
        }//check enemyFlight;


        for (vector<Bullet*>::iterator it = enemyBullet.begin();it!=enemyBullet.end();) {
            if(enemyBullet.empty()){
                break;
            }
            (*it)->drawImage(ourShader);
            if((*it)->checkEdge()||(*it)->checkCollision(myFlight)||(*it)->have_been_exploded){
                if((*it)->explode(currentTime,ourShader)){
                    delete (*it);
                    enemyBullet.erase(it);
                    continue;
                }
            }
            if(!(*it)->have_been_exploded){
                (*it)->move('S',deltaTime);
            }
            it++;
        }//check enemyBullet;


        glfwSwapBuffers(window);
        glfwPollEvents();

    }

    // optional: de-allocate all resources once they've outlived their purpose:
    // ------------------------------------------------------------------------
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteBuffers(1, &EBO);

    // glfw: terminate, clearing all previously allocated GLFW resources.
    // ------------------------------------------------------------------
    delete flight1;
    glfwTerminate();
    return 0;
}



// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    // make sure the viewport matches the new window dimensions; note that width and
    // height will be significantly larger than specified on retina displays.
    glViewport(0, 0, width, height);
}
